home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / Tools / linuxdoc-sgml-1.1 / sgmls-1.1 / xfprintf.c < prev   
Encoding:
C/C++ Source or Header  |  1995-05-03  |  10.4 KB  |  569 lines

  1. /* xfprintf.c -
  2.    X/Open extended v?fprintf implemented in terms of v?fprintf.
  3.  
  4.      Written by James Clark (jjc@jclark.com).
  5. */
  6.  
  7. /* Compile with:
  8.  
  9.    -DVARARGS            to use varargs.h instead of stdarg.h
  10.    -DLONG_DOUBLE_MISSING     if your compiler doesn't like `long double'
  11.    -DFP_SUPPORT                 to include floating point stuff
  12. */
  13.  
  14. #include "config.h"
  15.  
  16. #ifndef HAVE_EXTENDED_PRINTF
  17.  
  18. #include "std.h"
  19.  
  20. #ifdef lint
  21. /* avoid stupid lint warnings */
  22. #undef va_arg
  23. #define va_arg(ap, type) (ap, (type)0)
  24. #endif
  25.  
  26. #ifdef FP_SUPPORT
  27. #ifdef LONG_DOUBLE_MISSING
  28. typedef double long_double;
  29. #else
  30. typedef long double long_double;
  31. #endif
  32. #endif /* FP_SUPPORT */
  33.  
  34. #ifndef __STDC__
  35. #define const /* as nothing */
  36. #endif
  37.  
  38. #ifdef USE_PROTOTYPES
  39. #define P(parms) parms
  40. #else
  41. #define P(parms) ()
  42. #endif
  43.  
  44. #ifdef VARARGS
  45. typedef int (*printer)();
  46. #else
  47. typedef int (*printer)(UNIV, const char *, ...);
  48. #endif
  49.  
  50. enum arg_type {
  51.   NONE,
  52.   INT,
  53.   UNSIGNED,
  54.   LONG,
  55.   UNSIGNED_LONG,
  56. #ifdef FP_SUPPORT
  57.   DOUBLE,
  58.   LONG_DOUBLE,
  59. #endif /* FP_SUPPORT */
  60.   PCHAR,
  61.   PINT,
  62.   PLONG,
  63.   PSHORT
  64. };
  65.  
  66. union arg {
  67.   int i;
  68.   unsigned u;
  69.   long l;
  70.   unsigned long ul;
  71. #ifdef FP_SUPPORT
  72.   double d;
  73.   long_double ld;
  74. #endif /* FP_SUPPORT */
  75.   char *pc;
  76.   UNIV pv;
  77.   int *pi;
  78.   short *ps;
  79.   long *pl;
  80. };
  81.  
  82. #define NEXT 0
  83. #define MISSING 10
  84.  
  85. struct spec {
  86.   enum arg_type type;
  87.   char pos;
  88.   char field_width;
  89.   char precision;
  90. };
  91.  
  92. #define FLAG_CHARS "-+ #0"
  93.  
  94. static int parse_spec P((const char **, struct spec *));
  95. static int find_arg_types P((const char *, enum arg_type *));
  96. static void get_arg P((enum arg_type, va_list *, union arg *));
  97. static int do_arg P((UNIV, printer, const char *, enum arg_type, union arg *));
  98. static int xdoprt P((UNIV, printer, const char *, va_list));
  99. static int printit P((UNIV, printer, const char *, va_list, int, union arg *));
  100. static int maybe_positional P((const char *));
  101.  
  102. /* Return 1 if sucessful, 0 otherwise. **pp points to character after % */
  103.  
  104. static int parse_spec(pp, sp)
  105. const char **pp;
  106. struct spec *sp;
  107. {
  108.   char modifier = 0;
  109.   sp->pos = NEXT;
  110.   if (isdigit((unsigned char)(**pp)) && (*pp)[1] == '$') {
  111.     if (**pp == '0')
  112.       return 0;
  113.     sp->pos = **pp - '0';
  114.     *pp += 2;
  115.   }
  116.   
  117.   while (**pp != '\0' && strchr(FLAG_CHARS, **pp))
  118.     *pp += 1;
  119.   
  120.   /* handle the field width */
  121.  
  122.   sp->field_width = MISSING;
  123.   if (**pp == '*') {
  124.     *pp += 1;
  125.     if (isdigit((unsigned char)**pp) && (*pp)[1] == '$') {
  126.       if (**pp == '0')
  127.     return 0;
  128.       sp->field_width = **pp - '0';
  129.       *pp += 2;
  130.     }
  131.     else
  132.       sp->field_width = NEXT;
  133.   }
  134.   else {
  135.     while (isdigit((unsigned char)**pp))
  136.       *pp += 1;
  137.   }
  138.  
  139.   /* handle the precision */
  140.   sp->precision = MISSING;
  141.   if (**pp == '.') {
  142.     *pp += 1;
  143.     if (**pp == '*') {
  144.       *pp += 1;
  145.       if (isdigit((unsigned char)**pp) && (*pp)[1] == '$') {
  146.     if (**pp == '0')
  147.       return 0;
  148.     sp->precision = **pp - '0';
  149.     *pp += 2;
  150.       }
  151.       else
  152.     sp->precision = NEXT;
  153.     }
  154.     else {
  155.       while (isdigit((unsigned char)**pp))
  156.     *pp += 1;
  157.     }
  158.   }
  159.   /* handle h l or L */
  160.  
  161.   if (**pp == 'h' || **pp == 'l' || **pp == 'L') {
  162.     modifier = **pp;
  163.     *pp += 1;
  164.   }
  165.   
  166.   switch (**pp) {
  167.   case 'd':
  168.   case 'i':
  169.     sp->type = modifier == 'l' ? LONG : INT;
  170.     break;
  171.   case 'o':
  172.   case 'u':
  173.   case 'x':
  174.   case 'X':
  175.     sp->type = modifier == 'l' ? UNSIGNED_LONG : UNSIGNED;
  176.     break;
  177. #ifdef FP_SUPPORT
  178.   case 'e':
  179.   case 'E':
  180.   case 'f':
  181.   case 'g':
  182.   case 'G':
  183.     sp->type = modifier == 'L' ? LONG_DOUBLE : DOUBLE;
  184.     break;
  185. #endif /* FP_SUPPORT */
  186.   case 'c':
  187.     sp->type = INT;
  188.     break;
  189.   case 's':
  190.     sp->type = PCHAR;
  191.     break;
  192.   case 'p':
  193.     /* a pointer to void has the same representation as a pointer to char */
  194.     sp->type = PCHAR;
  195.     break;
  196.   case 'n':
  197.     if (modifier == 'h')
  198.       sp->type = PSHORT;
  199.     else if (modifier == 'l')
  200.       sp->type = PLONG;
  201.     else
  202.       sp->type = PINT;
  203.     break;
  204.   case '%':
  205.     sp->type = NONE;
  206.     break;
  207.   default:
  208.     return 0;
  209.   }
  210.   *pp += 1;
  211.   return 1;
  212. }
  213.  
  214.  
  215. static int find_arg_types(format, arg_type)
  216.      const char *format;
  217.      enum arg_type *arg_type;
  218. {
  219.   int i, pos;
  220.   const char *p;
  221.   struct spec spec;
  222.   
  223.   for (i = 0; i < 9; i++)
  224.     arg_type[i] = NONE;
  225.  
  226.   pos = 0;
  227.  
  228.   p = format;
  229.   while (*p)
  230.     if (*p == '%') {
  231.       p++;
  232.       if (!parse_spec(&p, &spec))
  233.     return 0;
  234.       if (spec.type != NONE) {
  235.     int n;
  236.     if (spec.pos == NEXT)
  237.       n = pos++;
  238.     else
  239.       n = spec.pos - 1;
  240.     if (n < 9) {
  241.       enum arg_type t = arg_type[n];
  242.       if (t != NONE && t != spec.type)
  243.         return 0;
  244.       arg_type[n] = spec.type;
  245.     }
  246.       }
  247.       if (spec.field_width != MISSING) {
  248.     int n;
  249.     if (spec.field_width == NEXT)
  250.       n = pos++;
  251.     else
  252.       n = spec.field_width - 1;
  253.     if (n < 9) {
  254.       enum arg_type t = arg_type[n];
  255.       if (t != NONE && t != INT)
  256.         return 0;
  257.       arg_type[n] = INT;
  258.     }
  259.       }
  260.       if (spec.precision != MISSING) {
  261.     int n;
  262.     if (spec.precision == NEXT)
  263.       n = pos++;
  264.     else
  265.       n = spec.precision - 1;
  266.     if (n < 9) {
  267.       enum arg_type t = arg_type[n];
  268.       if (t != NONE && t != INT)
  269.         return 0;
  270.       arg_type[n] = INT;
  271.     }
  272.       }
  273.     }
  274.     else
  275.       p++;
  276.   return 1;
  277. }
  278.  
  279. static void get_arg(arg_type, app, argp)
  280.      enum arg_type arg_type;
  281.      va_list *app;
  282.      union arg *argp;
  283. {
  284.   switch (arg_type) {
  285.   case NONE:
  286.     break;
  287.   case INT:
  288.     argp->i = va_arg(*app, int);
  289.     break;
  290.   case UNSIGNED:
  291.     argp->u = va_arg(*app, unsigned);
  292.     break;
  293.   case LONG:
  294.     argp->l = va_arg(*app, long);
  295.     break;
  296.   case UNSIGNED_LONG:
  297.     argp->ul = va_arg(*app, unsigned long);
  298.     break;
  299. #ifdef FP_SUPPORT
  300.   case DOUBLE:
  301.     argp->d = va_arg(*app, double);
  302.     break;
  303.   case LONG_DOUBLE:
  304.     argp->ld = va_arg(*app, long_double);
  305.     break;
  306. #endif /* FP_SUPPORT */
  307.   case PCHAR:
  308.     argp->pc = va_arg(*app, char *);
  309.     break;
  310.   case PINT:
  311.     argp->pi = va_arg(*app, int *);
  312.     break;
  313.   case PSHORT:
  314.     argp->ps = va_arg(*app, short *);
  315.     break;
  316.   case PLONG:
  317.     argp->pl = va_arg(*app, long *);
  318.     break;
  319.   default:
  320.     abort();
  321.   }
  322. }
  323.  
  324. static int do_arg(handle, func, buf, arg_type, argp)
  325.      UNIV handle;
  326.      printer func;
  327.      const char *buf;
  328.      enum arg_type arg_type;
  329.      union arg *argp;
  330. {
  331.   switch (arg_type) {
  332.   case NONE:
  333.     return (*func)(handle, buf);
  334.   case INT:
  335.     return (*func)(handle, buf, argp->i);
  336.   case UNSIGNED:
  337.     return (*func)(handle, buf, argp->u);
  338.   case LONG:
  339.     return (*func)(handle, buf, argp->l);
  340.   case UNSIGNED_LONG:
  341.     return (*func)(handle, buf, argp->ul);
  342. #ifdef FP_SUPPORT
  343.   case DOUBLE:
  344.     return (*func)(handle, buf, argp->d);
  345.   case LONG_DOUBLE:
  346.     return (*func)(handle, buf, argp->ld);
  347. #endif /* FP_SUPPORT */
  348.   case PCHAR:
  349.     return (*func)(handle, buf, argp->pc);
  350.   case PINT:
  351.     return (*func)(handle, buf, argp->pi);
  352.   case PSHORT:
  353.     return (*func)(handle, buf, argp->ps);
  354.   case PLONG:
  355.     return (*func)(handle, buf, argp->pl);
  356.   default:
  357.     abort();
  358.   }
  359.   /* NOTREACHED */
  360. }
  361.  
  362. static int printit(handle, func, p, ap, nargs, arg)
  363.      UNIV handle;
  364.      printer func;
  365.      const char *p;
  366.      va_list ap;
  367.      int nargs;
  368.      union arg *arg;
  369. {
  370.   char buf[512];        /* enough for a spec */
  371.   int count = 0;
  372.   int pos = 0;
  373.  
  374.   while (*p)
  375.     if (*p == '%') {
  376.       char *q;
  377.       struct spec spec;
  378.       const char *start;
  379.       int had_field_width;
  380.       union arg *argp;
  381.       union arg a;
  382.       int res;
  383.  
  384.       start = ++p;
  385.       if (!parse_spec(&p, &spec))
  386.     abort();        /* should have caught it in find_arg_types */
  387.       
  388.       buf[0] = '%';
  389.       q = buf + 1;
  390.  
  391.       if (spec.pos != NEXT)
  392.     start += 2;
  393.  
  394.       /* substitute in precision and field width if necessary */
  395.       had_field_width = 0;
  396.       while (start < p) {
  397.     if (*start == '*') {
  398.       char c;
  399.       int n, val;
  400.  
  401.       start++;
  402.       if (!had_field_width && spec.field_width != MISSING) {
  403.         c = spec.field_width;
  404.         had_field_width = 1;
  405.       }
  406.       else
  407.         c = spec.precision;
  408.       if (c == NEXT)
  409.         n = pos++;
  410.       else {
  411.         start += 2;
  412.         n = c - 1;
  413.       }
  414.       if (n >= nargs)
  415.         val = va_arg(ap, int);
  416.       else
  417.         val = arg[n].i;
  418.  
  419.       /* ignore negative precision */
  420.       if (val >= 0 || q[-1] != '.') {
  421.         (void)sprintf(q, "%d", val);
  422.         q = strchr(q, '\0');
  423.       }
  424.     }
  425.     else
  426.       *q++ = *start++;
  427.       }
  428.       *q++ = '\0';
  429.  
  430.       argp = 0;
  431.       if (spec.type != NONE) {
  432.     int n = spec.pos == NEXT ? pos++ : spec.pos - 1;
  433.     if (n >= nargs) {
  434.       get_arg(spec.type, &ap, &a);
  435.       argp = &a;
  436.     }
  437.     else
  438.       argp = arg + n;
  439.       }
  440.  
  441.       res = do_arg(handle, func, buf, spec.type, argp);
  442.       if (res < 0)
  443.     return -1;
  444.       count += res;
  445.     }
  446.     else {
  447.       if ((*func)(handle, "%c", *p++) < 0)
  448.     return -1;
  449.       count++;
  450.     }
  451.   return count;
  452. }
  453.  
  454. /* Do a quick check to see if it may contains any positional thingies. */
  455.  
  456. static int maybe_positional(format)
  457.      const char *format;
  458. {
  459.   const char *p;
  460.  
  461.   p = format;
  462.   for (;;) {
  463.     p = strchr(p, '$');
  464.     if (!p)
  465.       return 0;
  466.     if (p - format >= 2
  467.     && isdigit((unsigned char)p[-1])
  468.     && (p[-2] == '%' || p[-2] == '*'))
  469.       break;            /* might be a positional thingy */
  470.   }
  471.   return 1;
  472. }
  473.    
  474. static int xdoprt(handle, func, format, ap)
  475.      UNIV handle;
  476.      printer func;
  477.      const char *format;
  478.      va_list ap;
  479. {
  480.   enum arg_type arg_type[9];
  481.   union arg arg[9];
  482.   int nargs, i;
  483.  
  484.   if (!find_arg_types(format, arg_type))
  485.     return -1;
  486.   
  487.   for (nargs = 0; nargs < 9; nargs++)
  488.     if (arg_type[nargs] == NONE)
  489.       break;
  490.  
  491.   for (i = nargs; i < 9; i++)
  492.     if (arg_type[i] != NONE)
  493.       return -1;
  494.   
  495.   for (i = 0; i < nargs; i++)
  496.     get_arg(arg_type[i], &ap, arg + i);
  497.  
  498.   return printit(handle, func, format, ap, nargs, arg);
  499. }
  500.  
  501. #ifdef VARARGS
  502. static int do_fprintf(va_alist) va_dcl
  503. #else
  504. static int do_fprintf(UNIV p, const char *format,...)
  505. #endif
  506. {
  507. #ifdef VARARGS
  508.   UNIV p;
  509.   const char *format;
  510. #endif
  511.   va_list ap;
  512.   int res;
  513.  
  514. #ifdef VARARGS
  515.   va_start(ap);
  516.   p = va_arg(ap, UNIV);
  517.   format = va_arg(ap, char *);
  518. #else
  519.   va_start(ap, format);
  520. #endif
  521.  
  522.   res = vfprintf((FILE *)p, format, ap);
  523.   va_end(ap);
  524.   return res;
  525. }
  526.  
  527. #ifdef VARARGS
  528. int xfprintf(va_alist) va_dcl
  529. #else
  530. int xfprintf(FILE *fp, const char *format, ...)
  531. #endif
  532. {
  533. #ifdef VARARGS
  534.   FILE *fp;
  535.   char *format;
  536. #endif
  537.   va_list ap;
  538.   int res;
  539.  
  540. #ifdef VARARGS
  541.   va_start(ap);
  542.   fp = va_arg(ap, FILE *);
  543.   format = va_arg(ap, char *);
  544. #else
  545.   va_start(ap, format);
  546. #endif
  547.   if (maybe_positional(format))
  548.     res = xdoprt((UNIV)fp, do_fprintf, format, ap);
  549.   else
  550.     res = vfprintf(fp, format, ap);
  551.   va_end(ap);
  552.   return res;
  553. }
  554.  
  555. int xvfprintf(fp, format, ap)
  556.      FILE *fp;
  557.      const char *format;
  558.      va_list ap;
  559. {
  560.   int res;
  561.   if (maybe_positional(format))
  562.     res = xdoprt((UNIV)fp, do_fprintf, format, ap);
  563.   else
  564.     res = vfprintf(fp, format, ap);
  565.   return res;
  566. }
  567.  
  568. #endif /* not HAVE_EXTENDED_PRINTF */
  569.